name: CI

on:
  push:
    tags:
      - v*
    branches:
      - master
  pull_request:

jobs:
  build-libbpf-docker-x86_64:
    name: Build libbpf in Docker (x86_64)
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4

      - name: Build libbpf
        run: |
          docker buildx build --progress plain --tag libbpf --target libbpf_builder .
          id=$(docker create libbpf)
          docker cp $id:/build/libbpf.tar.gz libbpf.x86_64.tar.gz

      - name: Upload libbpf.tar.gz
        uses: actions/upload-artifact@v4
        with:
          name: libbpf.x86_64.tar.gz
          path: libbpf.x86_64.tar.gz
          if-no-files-found: error

  build-libbpf-docker-aarch64:
    name: Build libbpf in Docker (aarch64, emulated)
    runs-on: ubuntu-22.04
    steps:
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3
        with:
          platforms: arm64

      - uses: actions/checkout@v4

      - name: Build libbpf
        run: |
          docker buildx build --progress plain --tag libbpf --target libbpf_builder --platform linux/arm64 .
          id=$(docker create libbpf)
          docker cp $id:/build/libbpf.tar.gz libbpf.aarch64.tar.gz

      - name: Upload libbpf.tar.gz
        uses: actions/upload-artifact@v4
        with:
          name: libbpf.aarch64.tar.gz
          path: libbpf.aarch64.tar.gz
          if-no-files-found: error

  build-ebpf-exporter-docker-x86_64:
    name: Build ebpf_exporter in Docker (x86_64, built-in libbpf)
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0 # Fetch with tags to have the build version attached

      - name: Build ebpf_exporter and examples
        run: |
          docker buildx build --progress plain --tag ebpf_exporter .
          docker create --name ebpf_exporter ebpf_exporter

      - name: Extract ebpf_exporter.x86_64
        run: |
          docker cp ebpf_exporter:/ebpf_exporter ebpf_exporter

      - name: Upload ebpf_exporter
        uses: actions/upload-artifact@v4
        with:
          name: ebpf_exporter.x86_64
          path: ebpf_exporter
          if-no-files-found: error

      - name: Extract examples.x86_64.tar.gz
        run: |
          docker cp ebpf_exporter:/examples ./
          tar -cvzf examples.x86_64.tar.gz -T <(find examples | grep -E "\.(yaml|bpf.o)$")

      - name: Upload examples.x86_64.tar.gz
        uses: actions/upload-artifact@v4
        with:
          name: examples.x86_64.tar.gz
          path: examples.x86_64.tar.gz
          if-no-files-found: error

      - name: Extract ebpf_exporter_with_examples.x86_64.tar.gz
        run: |
          tar -cvzf ebpf_exporter_with_examples.x86_64.tar.gz --transform "s,\(.*\),ebpf_exporter-$(git describe --tags)/\1," -T <(echo ebpf_exporter; find examples | grep -E "\.(yaml|bpf.o)$" | sort)

      - name: Upload ebpf_exporter_with_examples.x86_64.tar.gz
        uses: actions/upload-artifact@v4
        with:
          name: ebpf_exporter_with_examples.x86_64.tar.gz
          path: ebpf_exporter_with_examples.x86_64.tar.gz
          if-no-files-found: error

  build-ebpf-exporter-docker-aarch64:
    name: Build ebpf_exporter in Docker (aarch64, emulated, built-in libbpf)
    runs-on: ubuntu-22.04
    steps:
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3
        with:
          platforms: arm64

      - uses: actions/checkout@v4
        with:
          fetch-depth: 0 # Fetch with tags to have the build version attached

      - name: Build ebpf_exporter and examples
        run: |
          docker buildx build --progress plain --tag ebpf_exporter --platform linux/arm64 .
          docker create --name ebpf_exporter ebpf_exporter

      - name: Extract ebpf_exporter.aarch64
        run: |
          docker cp ebpf_exporter:/ebpf_exporter ebpf_exporter

      - name: Upload ebpf_exporter
        uses: actions/upload-artifact@v4
        with:
          name: ebpf_exporter.aarch64
          path: ebpf_exporter
          if-no-files-found: error

      - name: Extract examples.aarch64.tar.gz
        run: |
          docker cp ebpf_exporter:/examples ./
          tar -cvzf examples.aarch64.tar.gz -T <(find examples | grep -E "\.(yaml|bpf.o)$")

      - name: Upload examples.aarch64.tar.gz
        uses: actions/upload-artifact@v4
        with:
          name: examples.aarch64.tar.gz
          path: examples.aarch64.tar.gz
          if-no-files-found: error

      - name: Extract ebpf_exporter_with_examples.aarch64.tar.gz
        run: |
          tar -cvzf ebpf_exporter_with_examples.aarch64.tar.gz --transform "s,\(.*\),ebpf_exporter-$(git describe --tags)/\1," -T <(echo ebpf_exporter; find examples | grep -E "\.(yaml|bpf.o)$" | sort)

      - name: Upload ebpf_exporter_with_examples.aarch64.tar.gz
        uses: actions/upload-artifact@v4
        with:
          name: ebpf_exporter_with_examples.aarch64.tar.gz
          path: ebpf_exporter_with_examples.aarch64.tar.gz
          if-no-files-found: error

  build-ebpf-exporter-static-x86_64-system-libbpf:
    name: Build ebpf_exporter (x86_64, statically linked, system libbpf)
    needs: build-libbpf-docker-x86_64
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-go@v5
        with:
          go-version: ^1.22

      - name: Download libbpf.tar.gz
        uses: actions/download-artifact@v4
        with:
          name: libbpf.x86_64.tar.gz

      - name: Install libbpf
        run: sudo tar -C / -xvvf libbpf.x86_64.tar.gz

      - name: Install libelf-dev
        run: sudo apt-get install -y libelf-dev

      - name: Build
        run: make -j $(nproc) build BUILD_LIBBPF=0

      - name: Check static linkage
        run: (ldd --verbose ./ebpf_exporter 2>&1 || true) | grep 'not a dynamic executable'

      - name: Check that it runs
        run: ./ebpf_exporter --version

  build-ebpf-exporter-static-x86_64-built-in-libbpf:
    name: Build ebpf_exporter (x86_64, statically linked, built-in libbpf)
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-go@v5
        with:
          go-version: ^1.22

      - name: Install libelf-dev
        run: sudo apt-get install -y libelf-dev

      - name: Build
        run: make -j $(nproc) build

      - name: Check static linkage
        run: (ldd --verbose ./ebpf_exporter 2>&1 || true) | grep 'not a dynamic executable'

      - name: Check that it runs
        run: ./ebpf_exporter --version

  build-ebpf-exporter-dynamic-x86_64-system-libbpf:
    name: Build ebpf_exporter (x86_64, dynamically linked, system libbpf)
    needs: build-libbpf-docker-x86_64
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-go@v5
        with:
          go-version: ^1.22

      - name: Download libbpf.tar.gz
        uses: actions/download-artifact@v4
        with:
          name: libbpf.x86_64.tar.gz

      - name: Install libbpf
        run: sudo tar -C / -xvvf libbpf.x86_64.tar.gz

      - name: Install libelf-dev
        run: sudo apt-get install -y libelf-dev

      - name: Build
        run: make -j $(nproc) build-dynamic BUILD_LIBBPF=0

      - name: Check dynamic linkage
        run: ldd --verbose ./ebpf_exporter

      - name: Check that it runs
        run: ./ebpf_exporter --version

  build-ebpf-exporter-dynamic-x86_64-built-in-libbpf:
    name: Build ebpf_exporter (x86_64, dynamically linked, built-in libbpf)
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-go@v5
        with:
          go-version: ^1.22

      - name: Install libelf-dev
        run: sudo apt-get install -y libelf-dev

      - name: Build
        run: make -j $(nproc) build-dynamic

      - name: Check dynamic linkage
        run: ldd --verbose ./ebpf_exporter

      - name: Check that it runs
        run: LD_LIBRARY_PATH=libbpf/dest/usr/lib ./ebpf_exporter --version

  test-ebpf-exporter-x86_64-system-libbpf:
    name: Test ebpf_exporter (x86_64, system libbpf)
    needs: build-libbpf-docker-x86_64
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-go@v5
        with:
          go-version: ^1.22

      - name: Download libbpf.tar.gz
        uses: actions/download-artifact@v4
        with:
          name: libbpf.x86_64.tar.gz

      - name: Install libbpf
        run: sudo tar -C / -xvvf libbpf.x86_64.tar.gz

      - name: Install libelf-dev
        run: sudo apt-get install -y libelf-dev

      - name: Update pci.ids
        run: |
          curl -o /tmp/pci.ids https://raw.githubusercontent.com/pciutils/pciids/master/pci.ids
          sudo mv /tmp/pci.ids /usr/share/misc/pci.ids

      - name: Test
        run: make -j $(nproc) test BUILD_LIBBPF=0

      - name: Test privileged
        run: make -j $(nproc) test-privileged BUILD_LIBBPF=0

  test-ebpf-exporter-x86_64-built-in-libbpf:
    name: Test ebpf_exporter (x86_64, built-in libbpf)
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-go@v5
        with:
          go-version: ^1.22

      - name: Install libelf-dev
        run: sudo apt-get install -y libelf-dev

      - name: Update pci.ids
        run: |
          curl -o /tmp/pci.ids https://raw.githubusercontent.com/pciutils/pciids/master/pci.ids
          sudo mv /tmp/pci.ids /usr/share/misc/pci.ids

      - name: Test
        run: make -j $(nproc) test

      - name: Test privileged
        run: make -j $(nproc) test-privileged

  lint-ebpf-exporter-x86_64-built-in-libbpf:
    name: Lint ebpf_exporter (x86_64, built-in libbpf)
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-go@v5
        with:
          go-version: ^1.22
          cache: false # https://github.com/golangci/golangci-lint-action/issues/807

      - name: Install libelf-dev
        run: sudo apt-get install -y libelf-dev

      - name: Build libbpf
        run: make -j $(nproc) libbpf.a

      - name: Check vendored dependencies
        run: go mod verify

      - name: Run golangci-lint
        uses: golangci/golangci-lint-action@c67416616c29c3c48d26b59c45cadb56966d80aa # https://github.com/golangci/golangci-lint-action/issues/953
        with:
          version: v1.54.2
        env:
          CGO_CFLAGS: "-I${{ github.workspace }}/libbpf/dest/usr/include"

  build-examples-x86_64-system-libbpf:
    name: Build examples (x86_64, system libbpf)
    needs: build-libbpf-docker-x86_64
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4

      - name: Download libbpf.tar.gz
        uses: actions/download-artifact@v4
        with:
          name: libbpf.x86_64.tar.gz

      - name: Install libbpf
        run: sudo tar -C / -xvvf libbpf.x86_64.tar.gz

      - name: Install libelf-dev
        run: sudo apt-get install -y libelf-dev

      - name: Install clang
        run: sudo apt-get install -y clang

      - name: Build benchmark bpf probes
        run: make -j $(nproc) -C benchmark build BUILD_LIBBPF=0

      - name: Build example bpf probes
        run: make -j $(nproc) -C examples build BUILD_LIBBPF=0

  build-examples-x86_64-built-in-libbpf:
    name: Build examples (x86_64, built-in libbpf)
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4

      - name: Install libelf-dev
        run: sudo apt-get install -y libelf-dev

      - name: Install clang
        run: sudo apt-get install -y clang

      - name: Build benchmark bpf probes
        run: make -j $(nproc) -C benchmark build

      - name: Build example bpf probes
        run: make -j $(nproc) -C examples build

  check-configs-x86_64:
    name: Check examples
    runs-on: ubuntu-22.04
    needs:
      - build-ebpf-exporter-docker-x86_64
    steps:
      - uses: actions/checkout@v4

      - name: Download ebpf_exporter_with_examples.x86_64.tar.gz
        uses: actions/download-artifact@v4
        with:
          name: ebpf_exporter_with_examples.x86_64.tar.gz

      - name: Extract ebpf_exporter_with_examples.x86_64.tar.gz
        run: tar --strip-components 1 -xzvf ebpf_exporter_with_examples.x86_64.tar.gz

      - name: Run configuration check
        run: make config-check

  clang-format:
    name: Run clang-format check
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4

      - name: Install clang-format
        run: sudo apt-get install -y clang-format make

      - name: Run clang-format check
        run: make clang-format-check

  jsonschema:
    name: Run jsonschema checks
    runs-on: ubuntu-22.04
    steps:
      - uses: actions/checkout@v4

      - name: Install jsonschema dependencies
        run: sudo apt-get install -y python3-jsonschema make

      - name: Install yq
        run: sudo curl -Lo /usr/bin/yq https://github.com/mikefarah/yq/releases/download/v4.35.2/yq_linux_amd64 && sudo chmod +x /usr/bin/yq

      - name: Run jsonschema check
        run: make jsonschema

  publish-docker-images:
    name: Publish Docker images (x86_64, aarch64)
    runs-on: ubuntu-22.04
    permissions:
      contents: read
      packages: write
    steps:
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3
        with:
          platforms: arm64

      - uses: actions/checkout@v4
        with:
          fetch-depth: 0 # Fetch with tags to have the build version attached

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Docker Metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ghcr.io/${{ github.repository }}
          tags: |
            type=raw,value=latest,enable={{is_default_branch}}
            type=ref,event=branch
            type=ref,event=tag
            type=ref,event=pr
            type=sha

      - name: Docker Login
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.repository_owner }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          platforms: linux/amd64,linux/arm64
          provenance: false # https://github.com/docker/build-push-action/issues/755
